﻿/*
 * Authors:    Kęstutis Džiautas
 *             Edmundas Matusevičius
 * University: VU, MIF, SE, 4 course
 * Date:       2010-10-23
 * Version:    1.1
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace LexAnalizer {
    class AutomatonStates {
        public AutomatonStates() {
            states = new Tree();
            parents = new Stack<TreeNode>();
            populateStatesTree();
        }

        /// <summary>
        /// Returns full tree of states.
        /// </summary>
        /// <returns>Tree object of states.</returns>
        public Tree getStatesTree() {
            return states;
        }

        /// <summary>
        /// Fills tree with states from xml file.
        /// </summary>
        private void populateStatesTree() {
            // check if states xml file exist
            if (File.Exists(statesFileName)) {
                XmlTextReader reader = new XmlTextReader(statesFileName);

                // condition element attributes
                string condId = "";
                string condAction = "";
                // state element attributes
                string stateName = "";
                string stateAction = "";
                // out element attributes
                string outId = "";
                string outLex = "";

                // last added node
                TreeNode lastNode = new TreeNode();

                // data object to be inserted into the node
                TreeNodeData data;

                // read xml file
                while (reader.Read()) {
                    switch (reader.NodeType) {
                        // found element start
                        case XmlNodeType.Element:
                            switch (reader.Name) {
                                #region condition element
                                case "cond":
                                    // clear attributes variables
                                    condId = "";
                                    condAction = "";

                                    // read attributes
                                    while (reader.MoveToNextAttribute()) {
                                        if (reader.Name.Equals("id")) {
                                            // id attribute value
                                            condId = reader.Value;
                                        } else {
                                            // action attribute value
                                            condAction = reader.Value;
                                        }
                                    }
                                    break;
                                #endregion
                                #region state element
                                case "state":
                                    // clear attributes variables
                                    stateName = "";
                                    stateAction = "";

                                    // read attributes
                                    while (reader.MoveToNextAttribute()) {
                                        if (reader.Name.Equals("name")) {
                                            // name attribute value
                                            stateName = reader.Value;
                                        } else {
                                            // action attribute value
                                            stateAction = reader.Value;
                                        }
                                    }

                                    // construct new data object
                                    data = new TreeNodeData();
                                    // action consists of condition (if any) and state elements actions
                                    data.action = ((condAction.Length == 0) ? "" : condAction + ";") + stateAction;
                                    data.condition = condId;
                                    data.state = stateName;

                                    // check if it is the first state element
                                    if (parents.Count == 0) {
                                        // add node to tree
                                        lastNode = states.addNode(data, null);
                                        // add node to stack, because found that node's xml start
                                        parents.Push(lastNode);
                                    } else {
                                        // add node to tree, parent becomes the node in stack's top
                                        lastNode = states.addNode(data, parents.Peek());
                                        // add node to stack, because found that node's xml start
                                        parents.Push(lastNode);
                                    }

                                    break;
                                #endregion
                                #region out element
                                case "out":
                                    // clear attributes variables
                                    outId = "";
                                    outLex = "";

                                    // read attributes
                                    while (reader.MoveToNextAttribute()) {
                                        if (reader.Name.Equals("id")) {
                                            // id attribute value
                                            outId = reader.Value;
                                        } else {
                                            // lexem attribute value
                                            outLex = reader.Value;
                                        }
                                    }

                                    // construct new data object
                                    data = new TreeNodeData();
                                    // action consists of condition (if any) and out element with parameters actions
                                    data.action = ((condAction.Length == 0) ? "" : condAction + ";") + "out(" + outId + "," + outLex + ")";
                                    data.condition = condId;
                                    data.state = "out";

                                    // add node to tree, parent becomes the node in stack's top
                                    states.addNode(data, parents.Peek());

                                    break;
                                #endregion
                                #region lookup element
                                case "lookup":
                                    // construct new data object
                                    data = new TreeNodeData();
                                    // action only to lookup
                                    data.action = "lookup";
                                    data.condition = condId;
                                    data.state = "lookup";

                                    // add node to tree, parent becomes the node in stack's top
                                    lastNode = states.addNode(data, parents.Peek());
                                    // add node to stack, because found that node's xml start
                                    parents.Push(lastNode);

                                    break;
                                #endregion
                            }
                            break;
                        // found element end
                        case XmlNodeType.EndElement:
                            switch (reader.Name) {
                                case "state":
                                case "lookup":
                                    // remove one node from stack, because found that node's xml end
                                    parents.Pop();
                                    break;
                            }
                            break;
                    }
                }
            } else {
                // cannot prepare tree, because no xml file was found
                states = null;
            }
        }

        /// <summary>
        /// States tree.
        /// </summary>
        private Tree states;
        /// <summary>
        /// Stack to follow the depth of xml tree.
        /// </summary>
        private Stack<TreeNode> parents;

        /// <summary>
        /// States xml file name.
        /// </summary>
        private const string statesFileName = "States.xml";
    }
}
